package api

import (
	"context"
	"errors"
	"fmt"
	"gateway/handle"
	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"golang.org/x/sync/errgroup"
	"net/http"
	"time"
)

type Config struct {
	Endpoint  string `help:"访问地址" default:""`
	Port      int    `help:"监听端口" default:"7659"`
	MaxSize   int64  `help:"上传对象最大大小" default:"1000000000"`
	OpenPprof bool   `help:"是否开启pprof" default:"true" releaseDefault:"false"`
}

type Server struct {
	config *Config
	*gin.Engine
	httpSrv *http.Server
	log     *zap.Logger
}
type Option func(s *Server)

func NewServer(
	log *zap.Logger,
	conf *Config,
	handle *handle.Handle,
) *Server {

	gin.SetMode(gin.DebugMode)
	g := gin.Default()

	s := &Server{
		config: conf,
		Engine: g,
		log:    log,
	}

	//注册静态路由
	s.POST("default", handle.PutObject)
	s.GET("/default/*object", handle.GetObject)
	s.HEAD("/default/*object", handle.HeadObject)

	if conf.OpenPprof {
		pprof.Register(g)
	}
	return s
}

func (s *Server) Run(ctx context.Context) error {
	addr := fmt.Sprintf("0.0.0.0:%d", s.config.Port)
	s.httpSrv = &http.Server{
		Addr:    addr,
		Handler: s,
	}

	var group errgroup.Group
	group.Go(func() error {
		s.log.Sugar().Infof("server start: %s; Endpoint: %s", addr, s.config.Endpoint)
		err := s.httpSrv.ListenAndServe()
		if err != nil && !errors.Is(err, http.ErrServerClosed) {
			s.log.Sugar().Fatalf("listen: %s\n", err)
			return err
		}
		return nil
	})

	group.Go(func() error {
		<-ctx.Done()
		ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
		defer cancel()
		if err := s.httpSrv.Shutdown(ctx); err != nil {
			s.log.Sugar().Fatal("Server forced to shutdown: ", err)
		}

		s.log.Sugar().Info("Server exiting")
		return nil
	})
	return group.Wait()
}
